home *** CD-ROM | disk | FTP | other *** search
- (herald (back_end parassign)
- (env t (orbit_top defs) (back_end closure) (back_end bookkeep)))
-
- ;;; Copyright (c) 1985 Yale University
- ;;; Authors: N Adams, R Kelsey, D Kranz, J Philbin, J Rees.
- ;;; This material was developed by the T Project at the Yale University Computer
- ;;; Science Department. Permission to copy this software, to redistribute it,
- ;;; and to use it for any purpose is granted, subject to the following restric-
- ;;; tions and understandings.
- ;;; 1. Any copy made of this software must include this copyright notice in full.
- ;;; 2. Users of this software agree to make their best efforts (a) to return
- ;;; to the T Project at Yale any improvements or extensions that they make,
- ;;; so that these may be included in future releases; and (b) to inform
- ;;; the T Project of noteworthy uses of this software.
- ;;; 3. All materials developed as a consequence of the use of this software
- ;;; shall duly acknowledge such use, in accordance with the usual standards
- ;;; of acknowledging credit in academic research.
- ;;; 4. Yale has made no warrantee or representation that the operation of
- ;;; this software will be error-free, and Yale is under no obligation to
- ;;; provide any services, by way of maintenance, update, or otherwise.
- ;;; 5. In conjunction with products arising from the use of this material,
- ;;; there shall be no use of the name of the Yale University nor of any
- ;;; adaptation thereof in any advertising, promotional, or sales literature
- ;;; without prior written consent from Yale in each case.
- ;;;
-
- ;;; Copyright (c) 1985 David Kranz
-
- (define-local-syntax (ass-comment string . rest)
- `(if *assembly-comments?*
- (emit-comment (format nil ,string ,@rest))))
-
- ;;; ALLOCATE-CALL The "top". Dispatch on the type of call.
-
- (define (allocate-call node)
- (if *call-break?* (breakpoint (pp-cps node)))
- (let ((proc (call-proc node)))
- (cond ((primop-node? proc)
- (ass-comment "~s" (pp-cps node))
- (allocate-primop-call node))
- ((lambda-node? proc)
- (generate-let node))
- ((variable-known (leaf-value proc))
- => (lambda (proc)
- (ass-comment "Call known procedure ~s"
- (cons (lambda-name proc) (cdr (pp-cps node))))
- (xcond ((fx= (call-exits node) 0)
- (allocate-known-return node proc))
- ((fx= (call-exits node) 1)
- (allocate-known-call node proc)))))
- ((fx= (call-exits node) 0)
- (ass-comment "Return from procedure ~s" (pp-cps node))
- (allocate-return node))
- ((fx= (call-exits node) 1)
- (ass-comment "Call unknown procedure ~s" (pp-cps node))
- (allocate-general-call node))
- (else
- (bug "too many exits - ~s" node)))))
-
- (define (allocate-known-call node proc)
- (receive (cont moved)
- (xselect (lambda-strategy proc)
- ((strategy/label) (allocate-label-call node proc))
- ((strategy/heap) (allocate-known-heap-call node proc)))
- (if (call-in-body? proc node)
- (cond (cont
- (generate-save-jump-and-link proc)
- (emit-stack-template cont moved)
- (restore-live-registers-and-continue moved cont))
- (else
- (generate-jump proc)
- (clear-slots)))
- (cond (cont
- (generate-save-avoid-jump-and-link proc)
- (emit-stack-template cont moved)
- (restore-live-registers-and-continue moved cont))
- (else
- (generate-avoid-jump proc)
- (clear-slots))))))
-
-
- (define-constant (maybe-deallocate-red-frame node)
- (emit maybe-popfr node))
-
- (define (allocate-known-heap-call node proc)
- (let* ((cont ((call-arg 1) node))
- (out? (lambda-node? cont)))
- (let ((moved (if out? (save-live-registers cont node) nil)))
- (parallel-assign-general node)
- (if (n-ary? proc)
- (generate-move (machine-num (length (call-args node))) NARGS))
- (or out? (maybe-deallocate-red-frame *lambda*))
- (return (and out? cont) moved))))
-
-
- (define (allocate-label-call node proc)
- (let* ((join (get-or-set-join-state node proc))
- (cont ((call-arg 1) node))
- (out? (lambda-node? cont)))
- (let ((moved (if out? (save-live-registers cont node) nil)))
- (parallel-assign node
- (cdr (call-args node))
- (join-point-arg-specs join)
- nil
- (join-point-global-registers join))
- (or out?
- (not (fully-recursive? proc))
- (maybe-deallocate-red-frame *lambda*))
- (return (and out? cont) moved))))
-
-
-
- (define (allocate-known-return node proc)
- (xselect (lambda-strategy proc)
- ((strategy/label) (allocate-label-return node proc))))
-
-
-
- (define (allocate-label-return node proc)
- (let ((join (get-or-set-join-state node proc)))
- (cond ((not (n-ary? proc))
- (parallel-assign node
- (call-args node)
- (join-point-arg-specs join)
- nil
- (join-point-global-registers join)))
- ((used? (lambda-cont-var proc))
- (let ((an-used? (and (any? lambda-node? (call-args node))
- (reg-node AN))))
- (if an-used? (free-register node AN))
- (parallel-assign node
- (call-args node)
- (join-point-arg-specs join)
- nil
- (join-point-global-registers join))
- (if an-used? (generate-move (or (register-loc an-used?)
- (temp-loc an-used?))
- AN))))
- (else
- (really-parallel-assign node '() '()
- (join-point-global-registers join) nil))))
- (clear-slots)
- (generate-jump proc))
-
- (define (allocate-conditional-continuation node proc-leaf)
- (error "This should not happen ALLOCATE-CONDITIONAL-CONTINUATION"))
-
-
- (define (allocate-general-call node)
- (let* ((cont ((call-arg 1) node))
- (out? (lambda-node? cont)))
- (let ((moved (if out? (save-live-registers cont node) nil)))
- (parallel-assign-general node)
- (cond (out?
- (generate-general-call-and-link (reference-variable (call-proc node))
- (fx- (length (call-args node)) 1))
- (emit-stack-template cont moved)
- (restore-live-registers-and-continue moved cont))
- (else
- (maybe-deallocate-red-frame *lambda*)
- (generate-general-call (reference-variable (call-proc node))
- (fx- (length (call-args node)) 1))
- (clear-slots))))))
-
-
- (define (allocate-return node)
- (parallel-assign-return node)
- (maybe-deallocate-red-frame *lambda*)
- (clear-slots)
- (generate-return (length (call-args node))))
-
-
-
-
- (define (parallel-assign-general node)
- (parallel-assign node (cons (call-proc node) (cdr (call-args node)))
- nil t '()))
-
- (define (parallel-assign-return node)
- (parallel-assign node (call-args node) nil nil '()))
-
-
- ;;; PARALLEL-ASSIGN Cons a closure if necessary. It is known that there
- ;;; will only be one that needs to be consed.
-
- (define (parallel-assign node args p-list proc? solve-list)
- (let ((an-locked? (cond ((get-closure args)
- => (lambda (closure)
- (make-heap-closure node closure)
- (lock AN)
- t))
- (else nil))))
- (receive (args pos-list) (do-reg-positions node args p-list proc?)
- (really-parallel-assign node args pos-list solve-list an-locked?))))
-
-
- (define (get-closure args)
- (any (lambda (arg)
- (and (lambda-node? arg)
- (eq? (lambda-strategy arg) strategy/heap)
- (neq? (environment-closure (lambda-env arg)) *unit*)
- (environment-closure (lambda-env arg))))
- args))
-
-
- ;;; do-now - register or temp pairs (source . target)
- ;;; trivial - immediate or lambda
- ;;; do-later - environment
- ;;; See implementor for this stuff. Hairy!!
-
- (define-structure-type arg-mover
- from
- to
- (((print self port)
- (format port "{Arg-mover (~d ~d)}" (arg-mover-from self) (arg-mover-to self)))))
-
- (define (mover from to)
- (let ((a (make-arg-mover)))
- (set (arg-mover-from a) from)
- (set (arg-mover-to a) to)
- a))
-
- (define (really-parallel-assign node args pos-list solve-list unlock?)
- (receive (do-now trivial do-later) (sort-by-difficulty args pos-list)
- (receive (do-now do-later) (add-on-free-list do-now do-later solve-list)
- (solve node do-now do-later)
- (do-indirects node do-later)
- (walk (lambda (pair)
- (if (lambda-node? (car pair))
- (do-trivial-lambda (car pair) (cdr pair))))
- trivial)
- (if unlock? (unlock AN))
- (walk (lambda (pair)
- (if (not (lambda-node? (car pair)))
- (do-immediate (car pair) (cdr pair))))
- trivial))))
-
-
- (define (add-on-free-list do-now do-later solve-list)
- (iterate loop ((pairs solve-list) (do-now do-now) (do-later do-later))
- (cond ((null? pairs)
- (return do-now do-later))
- ((or (register-loc (cdar pairs))
- (temp-loc (cdar pairs)))
- => (lambda (reg)
- (loop (cdr pairs)
- (cons (mover reg (caar pairs))
- do-now)
- do-later)))
- (else
- (loop (cdr pairs)
- do-now
- (if (fx= (caar pairs) P)
- (append! do-later (list (cons (cdar pairs) P)))
- (cons (cons (cdar pairs) (caar pairs))
- do-later)))))))
-
-
- (define (sort-by-difficulty args pos-list)
- (iterate loop ((args args) (do-now '()) (trivial '()) (do-later '())
- (pos-list pos-list))
- (cond ((null? args)
- (return do-now trivial do-later))
- ((lambda-node? (car args))
- (let ((l (car args)))
- (cond ((eq? (environment-closure (lambda-env l)) *unit*)
- (loop (cdr args)
- do-now
- trivial
- (cons (cons l (car pos-list)) do-later)
- (cdr pos-list)))
- (else
- (loop (cdr args)
- do-now
- (cons (cons l (car pos-list)) trivial)
- do-later
- (cdr pos-list))))))
- ((addressable? (leaf-value (car args)))
- (loop (cdr args)
- do-now
- (cons (cons (car args) (car pos-list)) trivial)
- do-later
- (cdr pos-list)))
- (else
- (let* ((val (leaf-value (car args)))
- (value (cond ((and (variable? val) (variable-known val))
- => lambda-self-var)
- (else val))))
- (cond ((let ((reg (register-loc value))
- (temp (temp-loc value)))
- (if (and reg temp (eq? temp (car pos-list)))
- temp
- (or reg temp)))
- => (lambda (reg)
- (loop (cdr args)
- (cons (mover reg (car pos-list))
- do-now)
- trivial
- do-later
- (cdr pos-list))))
- (else
- (loop (cdr args)
- do-now
- trivial
- (if (fx= (car pos-list) P)
- (append! do-later (list (cons value (car pos-list))))
- (cons (cons value (car pos-list)) do-later))
- (cdr pos-list)))))))))
-
-
- (define (do-immediate node reg)
- (generate-move-addressable (leaf-value node) reg))
-
-
- (define (do-indirects node do-later)
- (iterate loop ((items do-later))
- (if items
- (let ((item (car items))
- (contour (lambda-self-var *heap-env*)))
- (receive (mover target) (get-mover-and-target item)
- (cond ((eq? (register-loc contour) target)
- (if (cdr items)
- (loop (append (cdr items) (cons item '())))
- (mover node (car item) target)))
- ((eq? (temp-loc contour) target)
- (cond ((not (cdr items))
- (mover node (car item) target))
- ((receive (#f target) (get-mover-and-target (cadr items))
- (eq? (register-loc contour) target))
- (set (temp-loc contour) nil)
- (set (temp-node target) nil)
- (mover node (car item) target)
- (loop (cdr items)))
- (else
- (loop (append (cdr items) (cons item '()))))))
- (else
- (mover node (car item) target)
- (loop (cdr items)))))))))
-
- (define (get-mover-and-target item)
- (cond ((and (node? (car item))
- (lambda-node? (car item)))
- (return indirect-lambda (cdr item)))
- (else
- (return indirect-var (cdr item)))))
-
-
-
- (define (indirect-lambda node lam target)
- (lambda-queue lam)
- (generate-move (lookup node lam nil) target)
- (unmark-reg target)
- (lock target))
-
- (define (indirect-var node var target)
- (generate-move (lookup-value node var) target)
- (unmark-reg target)
- (mark var target)
- (lock target))
-
-
-
- (define (unmark-reg reg)
- (cond ((reg-node reg)
- => (lambda (var)
- (set (reg-node reg) nil)
- (if (register? reg)
- (set (register-loc var) nil)
- (set (temp-loc var) nil))))))
-
-
- (define (solve node movers do-later)
- (let* ((contour (lambda-self-var *heap-env*))
- (tos (map arg-mover-to movers))
- (vals (map reg-node tos))
- (real-movers (filter need-to-move? movers))
- (save-env
- (and do-later
- (any (lambda (mover)
- (if (eq? (reg-node (arg-mover-to mover)) contour)
- mover
- nil))
- movers)))
- (reg (or (register-loc contour) (temp-loc contour))))
- (walk kill vals)
- (walk lock tos)
- (cond ((not save-env))
- ((neq? (arg-mover-from save-env) (arg-mover-to save-env))
- (let ((new (get-stack-slot node)))
- (generate-move reg new)
- (mark contour new)))
- (else
- (mark contour (arg-mover-to save-env))))
- (do-assignment real-movers node)))
-
- (define-constant (need-to-move? mover)
- (not (eq? (reg-node (arg-mover-from mover))
- (reg-node (arg-mover-to mover)))))
-
-
- (define (do-assignment movers node)
- (iterate loop1 ((movers movers)
- (targets (map arg-mover-to movers))
- (temp nil))
- (cond ((null? movers))
- (else
- (iterate loop2 ((candidates targets))
- (cond ((null? candidates)
- (let ((mover (car movers)))
- (generate-move (arg-mover-to mover) parassign-extra)
- (generate-move (arg-mover-from mover) (arg-mover-to mover))
- (loop1 (cdr movers)
- (delq (arg-mover-to mover) targets)
- (arg-mover-to mover))))
- ((not (mem? from-reg-eq? (car candidates) movers))
- (let ((mover (car (mem to-reg-eq? (car candidates) movers))))
- (generate-move
- (cond ((eq? (arg-mover-from mover) temp) parassign-extra)
- (else
- (arg-mover-from mover)))
- (arg-mover-to mover))
- (loop1 (delq mover movers)
- (delq (arg-mover-to mover) targets)
- temp)))
- (else
- (loop2 (cdr candidates)))))))))
-
-
-
-
- (define (to-reg-eq? reg mover) (fx= (arg-mover-to mover) reg))
- (define (from-reg-eq? reg mover) (fx= (arg-mover-from mover) reg))
-
-
- (define (save-live-registers cont node)
- (modify (lambda-max-temps *lambda*) ;make sure we have stack frame here
- (lambda (max-temp)
- (max 1 max-temp)))
- (iterate loop ((vars (if '#t ;fill in later
- (let ((contour (lambda-self-var *heap-env*))
- (live (lambda-live cont)))
- (if (memq? contour live)
- live
- (cons contour live)))
- (lambda-live cont)))
- (moved '()))
- (if (null? vars)
- moved
- (let* ((var (car vars))
- (mover
- (cond ((temp-loc var)
- => (lambda (temp)
- (let ((reg (register-loc var)))
- (if (and reg (fx>= reg *first-stack-register*))
- (cons var (cons reg temp))
- (cons var temp)))))
- ((register-loc var)
- => (lambda (reg)
- (cond ((fx>= reg *first-stack-register*)
- (cons var reg))
- (else
- (let ((new
- (cond
- ((likely-next-reg var cont)
- => (lambda (new)
- (if (or (reg-node new)
- (fx< new *first-stack-register*))
- (get-stack-slot node)
- new)))
- (else
- (get-stack-slot node)))))
- (generate-move reg new)
- (lock new)
- (cons var new))))))
- (else '#f))))
- (if mover
- (loop (cdr vars) (cons mover moved))
- (loop (cdr vars) moved))))))
-
- (define (restore-live-registers-and-continue moved cont)
- (let ((node (lambda-body cont)))
- (clear-slots)
- (if (nary-setup-needed? cont)
- (generate-nary-setup cont (length (lambda-variables cont))))
- (do ((vars (lambda-variables cont) (cdr vars))
- (reg A1 (fx+ reg 1)))
- ((or (fx>= reg AN) (null? vars))
- (cond (vars
- (let ((used (used-registers moved)))
- (do ((vars vars (cdr vars))
- (reg (next-not-used *first-stack-register* used)
- (next-not-used (fx+ reg 1) used)))
- ((null? vars)
- (modify (lambda-max-temps *lambda*)
- (lambda (temps) (max temps (fx- reg 1)))))
- (cond ((and (car vars) (variable-refs (car vars)))
- (mark (car vars) reg)
- (generate-extra-arg-move reg))))))))
- (cond ((and (car vars) (variable-refs (car vars)))
- (mark (car vars) reg))))
- (walk (lambda (moved)
- (destructure (((var . regs) moved))
- (cond ((atom? regs)
- (mark var regs))
- (else
- (mark var (car regs)) ;reg
- (mark var (cdr regs)))))) ;temp
- moved)
- (allocate-call node)))
-
- (define (next-not-used reg moved)
- (cond ((memq? reg moved)
- (next-not-used (fx+ reg 1) moved))
- (else reg)))
-
- (define (used-registers moved)
- (iterate loop ((moved moved) (used '()))
- (cond ((null? moved) used)
- (else
- (destructure (((#f . regs) (car moved)))
- (if (atom? regs)
- (loop (cdr moved) (cons regs used))
- (loop (cdr moved) (cons (car regs) (cons (cdr regs) used)))))))))
-
- ;; the following is to special case a join which is nary and used to
- ;; strategy/stack in non-risc versions
-
- (define (nary-setup-needed? node)
- (and (n-ary? node)
- (or (used? (lambda-rest-var node))
- (let* ((body (lambda-body node))
- (proc (call-proc body)))
- (and (fx= (call-exits body) 0)
- (reference-node? proc)
- (let ((known (variable-known (reference-variable proc))))
- (and known (n-ary? known))))))))
-
-